var AppalachianListener = {};

AppalachianListener.start = function(origin, method, destination) {
    Appalachian._observer = new AppalachianObserver(origin, method, destination);
    AppalachianListener.addObserver(Appalachian._observer);
};

AppalachianListener.stop = function() {
    AppalachianListener.removeObserver(Appalachian._observer);
    Appalachian._observer = null;
}

AppalachianListener.addObserver = function(obj) {
    var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
    observerService.addObserver(obj, "http-on-modify-request", false);
    observerService.addObserver(obj, "http-on-examine-response", false);
};

AppalachianListener.removeObserver = function(obj) {
    var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
    observerService.removeObserver(obj, "http-on-modify-request", false);
    observerService.removeObserver(obj, "http-on-examine-response", false);
};

var AppalachianObserver = function(origin, method, destination) {
    this.origin = origin;
    this.method = method;
    this.destination = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(origin, null, null).resolve(destination);
    this.channel;
};

AppalachianObserver.prototype.observe = function(subject, topic, data) {
    if (topic == 'http-on-modify-request') {
        subject.QueryInterface(Components.interfaces.nsIHttpChannel);
        this.doRequest(subject);
    } else if (topic == 'http-on-examine-response') {
        subject.QueryInterface(Components.interfaces.nsIHttpChannel);
        this.doResponse(subject);
    }
};

AppalachianObserver.prototype.doRequest = function(req) {
    if (req && req.referrer) {
        if (req.referrer.asciiSpec == this.origin &&
        req.requestMethod.toLowerCase() == this.method.toLowerCase() &&
        req.URI.asciiSpec == this.destination) {
            this.channel = req;
        }
    }
};

AppalachianObserver.prototype.doResponse = function(resp) {
    if (resp == this.channel) {
        this.channel = null;
        var location;
        var status = resp.responseStatus;
        if (status == 301 || status == 302) {
            // this is the most likely case: a redirect to
            // an identity provider's services; 301 is a bad
            // answer, but it is worth examining
            location = resp.getResponseHeader('Location');
        } else {
            // this is likely to be a fraudulent attempt since
            // the answer to an identity question is unlikely
            // to be answered by the same server (unless
            // it's a server error - one should hope this isn't
            // the case, but server errors could still be
            // veiled phishing attempts - so check anyways)
            location = this.destination;
        }
        Appalachian.getState().advance(APPALACHIAN_ACTION_OBSERVED_REDIRECT);
        Appalachian.verify(location);
    }
};

AppalachianObserver.prototype.QueryInterface = function(iid) {
    if (!iid.equals(Components.interfaces.nsISupports) &&
        !iid.equals(Components.interfaces.nsIHttpNotify) &&
        !iid.equals(Components.interfaces.nsIObserver)) {
          throw Components.results.NS_ERROR_NO_INTERFACE;
    }
    return this;
};
